using FireStarter.Base;
using Firestarter.DB.Schema.BO;
using FireStarterModeller.BO;
using FireStarterModeller.Logic;
using FireStarterModeller.Test;
using FireStarterModeller.Test.BO;
using NUnit.Framework;
 
using Rhino.Mocks;

namespace Firestarter.DB_DomainModel.Logic.Test.DBChangesImporterTests
{
    [TestFixture]
    public class TestDBChangesImporter_ChangeTypeIsDelete : TestBase
    {
        private static DBChangesImporter CreateDBChangesImporter()
        {
            IDBTypeToDMPropertyTypeMapper propertyTypeMapper = MockRepository.GenerateStub<IDBTypeToDMPropertyTypeMapper>();
            DBToDMImporterFactory factory = new DBToDMImporterFactory(propertyTypeMapper, new RelationshipNameGenerator());
            return new DBChangesImporter(factory);
        }

        private static DBTable CreateTableWithoutMappedClass()
        {
            DBDatabase database = new DBDatabase();
            DBTable table = new DBTable(TestUtilsShared.GetRandomString()).ApproveForAdd();
            database.Tables.Add(table);
            DMSolution solution = TestUtilsDMSolution.CreateUnsavedValidDMSolution();
            return table;
        }
        private static DBTable CreateTableWithMappedClass()
        {
            DBDatabase database = new DBDatabase();
            DBTable table = new DBTable(TestUtilsShared.GetRandomString()).ApproveForAdd();
            database.Tables.Add(table);
            DMSolution solution = TestUtilsDMSolution.CreateUnsavedValidDMSolution();
            DBChangesImporter importer = CreateDBChangesImporter();
            importer.ImportDBChanges(database, solution);
            return table;
        }

        private static DBColumn CreateColumnWithMappedProperty()
        {
            DBDatabase database = new DBDatabase();
            DBTable table = new DBTable(TestUtilsShared.GetRandomString());
            database.Tables.Add(table.ApproveForAdd());
            DBTableBuilder builder = new DBTableBuilder(table);
            DBColumn column = builder.AddPrimaryKeyColumn().Column;
            column.Nullable = TestUtilsShared.GetRandomBoolean();
            column.ApproveForAdd();
            DMSolution solution = TestUtilsDMSolution.CreateUnsavedValidDMSolution();
            IDBChangesImporter importer = CreateDBChangesImporter();
            importer.ImportDBChanges(database, solution);
            return column;
        }

        private static DBPrimaryKey CreatePrimaryKeyWithMappedObjectIdentity()
        {
            DBDatabase database = new DBDatabase();
            DBTable table = new DBTable(TestUtilsShared.GetRandomString()).ApproveForAdd();
            database.Tables.Add(table);
            DBTableBuilder builder = new DBTableBuilder(table);
            builder.AddPrimaryKeyColumn().ApproveForAdd().Column.ApproveForAdd();
            DBPrimaryKey dbPrimaryKey = table.PrimaryKeyDB.ApproveForAdd();
            DMSolution solution = TestUtilsDMSolution.CreateUnsavedValidDMSolution();
            DBChangesImporter importer = CreateDBChangesImporter();
            importer.ImportDBChanges(database, solution);
            return dbPrimaryKey;
        }

        private static DBKey CreateAlternateKeyWithMappedUniqueConstraint()
        {
            DBDatabase database = new DBDatabase();
            DBTable table = new DBTable(TestUtilsShared.GetRandomString()).ApproveForAdd();
            database.Tables.Add(table);
            DBTableBuilder builder = new DBTableBuilder(table);
            builder.AddUniqueKeyColumn("ExistingAKColumn").ApproveForAdd();
            DBKey dbKey = table.Keys[0].ApproveForAdd();
            DMSolution solution = TestUtilsDMSolution.CreateUnsavedValidDMSolution();
            DBChangesImporter importer = CreateDBChangesImporter();
            importer.ImportDBChanges(database, solution);
            return dbKey;
        }

        private static DBForeignKey CreateForeignKeyWithMappedRelationship()
        {
            DBDatabase database = new DBDatabase();
            string tableName1 = TestUtilsShared.GetRandomString();
            DBTable table1 = new DBTable(tableName1).ApproveForAdd();
            database.Tables.Add(table1);
            string tableName2 = TestUtilsShared.GetRandomString();
            DBTable table2 = new DBTable(tableName2).ApproveForAdd();
            database.Tables.Add(table2);

            DBTableBuilder builder1 = new DBTableBuilder(table1);
            builder1.AddPrimaryKeyColumn().ApproveForAdd();

            DBTableBuilder builder2 = new DBTableBuilder(table2);
            DBForeignKey foreignKey = builder2.AddForeignKey(TestUtilsShared.GetRandomString(), table1).ApproveForAdd();
            foreignKey.ForeignKeyColumns[0].ApproveForAdd().ParentColumn.ApproveForAdd();
            foreignKey.ForeignKeyColumns[0].ApproveForAdd().RelatedColumn.ApproveForAdd();

            DMSolution solution = TestUtilsDMSolution.CreateUnsavedValidDMSolution();
            DBChangesImporter importer = CreateDBChangesImporter();
            importer.ImportDBChanges(database, solution);
            return foreignKey;
        }

        [Test]
        public void Test_ImportDBChanges_DeletedDBTables_ShouldDeleteApproved()
        {
            //---------------Set up test pack-------------------
            IDBChangesImporter importer = CreateDBChangesImporter();
            DBTable table = CreateTableWithMappedClass().ApproveForDelete();
            DMClass mappedClass = table.GetMappedDMClass();
            IDBDatabase database = table.Database;
            DMSolution solution = mappedClass.Solution as DMSolution;
            //---------------Assert Precondition----------------
            Assert.IsNotNull(solution);
            Assert.That(solution.AllClasses.Count, Is.EqualTo(database.Tables.Count));
            Assert.That(mappedClass.Properties.Count, Is.EqualTo(0));
            Assert.That(database.Tables.Count, Is.EqualTo(1));
            Assert.That(solution.DefaultAssembly, Is.Not.Null);
            Assert.That(solution.Assemblies.Contains(solution.DefaultAssembly));
            //---------------Execute Test ----------------------
            importer.ImportDBChanges(database, solution);
            //---------------Test Result -----------------------
            Assert.That(solution.AllClasses.Count, Is.EqualTo(0));
            Assert.That(database.Tables.Count, Is.EqualTo(0));
        }
        [Test]
        public void Test_ImportDBChanges_DeletedDBTables_WithNoMappedDMClass_ShouldDeleteApproved_FIXBUGBug884()
        {
            //---------------Set up test pack-------------------
            IDBChangesImporter importer = CreateDBChangesImporter();
            DBTable table = CreateTableWithoutMappedClass().ApproveForDelete();
            IDBDatabase database = table.Database;
            DMSolution solution = new SolutionCreator().CreateSolution();
            //---------------Assert Precondition----------------
            Assert.IsNotNull(solution);
            Assert.That(database.Tables.Count, Is.EqualTo(1));
            Assert.IsNull(table.GetMappedDMClass());
            //---------------Execute Test ----------------------
            importer.ImportDBChanges(database, solution);
            //---------------Test Result -----------------------
            Assert.That(solution.AllClasses.Count, Is.EqualTo(0));
            Assert.That(database.Tables.Count, Is.EqualTo(0));
        }

        [Test]
        public void Test_ImportDBChanges_DeletedDBTables_ShouldNotDeleteUnapproved()
        {
            IDBChangesImporter importer = CreateDBChangesImporter();
            DBTable table = CreateTableWithMappedClass().UnApproveForDelete();
            DMClass mappedClass = table.GetMappedDMClass();
            IDBDatabase database = table.Database;
            var solution = mappedClass.Solution;
            //---------------Assert Precondition----------------
            Assert.That(solution.AllClasses.Count, Is.EqualTo(1));
            Assert.That(database.Tables.Count, Is.EqualTo(1));
            //---------------Execute Test ----------------------
            importer.ImportDBChanges(database, (DMSolution) solution);
            //---------------Test Result -----------------------
            Assert.That(solution.AllClasses.Count, Is.EqualTo(1));
            Assert.That(database.Tables.Count, Is.EqualTo(1));
            table.AssertIsUnApprovedAndPendingChangeTypeIs(ChangeType.Delete);
        }

        [Test]
        public void Test_ImportDBChanges_DeletedDBProps_ShouldDeleteApproved()
        {
            //---------------Set up test pack-------------------
            IDBChangesImporter importer = CreateDBChangesImporter();
            DBColumn column = CreateColumnWithMappedProperty().ApproveForDelete();
            IDMProperty property = column.GetMappedDMProperty();
            DBTable table = column.Table;
            IDBDatabase database = table.Database;
            IDMClass mappedClass = property.Class;
            var solution = mappedClass.Solution;
            //---------------Assert Precondition----------------
            Assert.That(solution.AllClasses.Count, Is.EqualTo(database.Tables.Count));
            Assert.That(mappedClass.Properties.Count, Is.EqualTo(table.Columns.Count));
            Assert.That(table.Columns.Count, Is.Not.EqualTo(0));
            Assert.That(solution.DefaultAssembly, Is.Not.Null);
            //---------------Execute Test ----------------------
            importer.ImportDBChanges(database, (DMSolution) solution);
            //---------------Test Result -----------------------
            Assert.That(solution.AllClasses.Count, Is.EqualTo(database.Tables.Count));
            Assert.That(mappedClass.Properties.Count, Is.EqualTo(0));
            Assert.That(table.Columns.Count, Is.EqualTo(0));
        }

        [Test]
        public void Test_ImportDBChanges_DeletedDBProps_ShouldNotDeleteUnapproved()
        {
            //---------------Set up test pack-------------------
            IDBChangesImporter importer = CreateDBChangesImporter();
            DBColumn column = CreateColumnWithMappedProperty().UnApproveForDelete();
            IDMProperty property = column.GetMappedDMProperty();
            var table = column.Table;
            IDBDatabase database = table.Database;
            IDMClass mappedClass = property.Class;
            DMSolution solution = (DMSolution) mappedClass.Solution;
            //---------------Assert Precondition----------------
            Assert.That(solution.AllClasses.Count, Is.EqualTo(database.Tables.Count));
            Assert.That(mappedClass.Properties.Count, Is.EqualTo(table.Columns.Count));
            Assert.That(table.Columns.Count, Is.Not.EqualTo(0));
            Assert.That(solution.DefaultAssembly, Is.Not.Null);
            //---------------Execute Test ----------------------
            importer.ImportDBChanges(database, solution);
            //---------------Test Result -----------------------
            Assert.That(solution.AllClasses.Count, Is.EqualTo(database.Tables.Count));
            Assert.That(mappedClass.Properties.Count, Is.EqualTo(table.Columns.Count));
            Assert.That(table.Columns.Count, Is.Not.EqualTo(0));
            column.AssertIsUnApprovedAndPendingChangeTypeIs(ChangeType.Delete);
        }

        [Test]
        public void Test_ImportDBChanges_DeletedDBPrimaryKey_ShouldDeleteApproved()
        {
            //---------------Set up test pack-------------------
            IDBChangesImporter importer = CreateDBChangesImporter();
            DBPrimaryKey dbPrimaryKey = CreatePrimaryKeyWithMappedObjectIdentity().ApproveForDelete();
            DBTable table = (DBTable)dbPrimaryKey.Table;
            DMClass mappedClass = table.GetMappedDMClass();
            DMObjectIdentity objectIdentity = mappedClass.ObjectIdentity;
            //---------------Assert Precondition----------------
            Assert.That(objectIdentity, Is.Not.Null);
            Assert.That(objectIdentity.Properties.Contains(dbPrimaryKey.PrimaryKeyColumns[0].Column.GetMappedDMProperty()));
            //---------------Execute Test ----------------------
            importer.ImportDBChanges(table.Database, (DMSolution) mappedClass.Solution);
            //---------------Test Result -----------------------
            Assert.That(mappedClass.ObjectIdentity, Is.Null);
            Assert.IsTrue(objectIdentity.Status.IsDeleted);
            Assert.IsNull(table.PrimaryKeyDB);
        }

        [Test]
        public void Test_ImportDBChanges_DeletedDBPrimaryKey_ShouldNotDeleteUnapproved()
        {
            //---------------Set up test pack-------------------
            IDBChangesImporter importer = CreateDBChangesImporter();
            DBPrimaryKey dbPrimaryKey = CreatePrimaryKeyWithMappedObjectIdentity().UnApproveForDelete();
            DBTable table = (DBTable)dbPrimaryKey.Table;
            DMClass mappedClass = table.GetMappedDMClass();
            DMObjectIdentity objectIdentity = mappedClass.ObjectIdentity;
            //---------------Assert Precondition----------------
            Assert.That(objectIdentity, Is.Not.Null);
            Assert.That(objectIdentity.Properties.Contains(dbPrimaryKey.PrimaryKeyColumns[0].Column.GetMappedDMProperty()));
            //---------------Execute Test ----------------------
            importer.ImportDBChanges(table.Database, (DMSolution) mappedClass.Solution);
            //---------------Test Result -----------------------
            Assert.That(mappedClass.ObjectIdentity, Is.Not.Null);
            Assert.IsFalse(objectIdentity.Status.IsDeleted);
            Assert.IsNotNull(table.PrimaryKeyDB);
            dbPrimaryKey.AssertIsUnApprovedAndPendingChangeTypeIs(ChangeType.Delete);
        }

        [Test]
        public void Test_ImportDBChanges_DeletedDBKey_ShouldDeleteApproved()
        {
            //---------------Set up test pack-------------------
            IDBChangesImporter importer = CreateDBChangesImporter();
            DBKey dbKey = CreateAlternateKeyWithMappedUniqueConstraint().ApproveForDelete();
            DBTable table = (DBTable)dbKey.Table;
            DMClass mappedClass = table.GetMappedDMClass();
            DMUniqueConstraint uniqueConstraint = mappedClass.UniqueConstraints[0];
            //---------------Assert Precondition----------------
            Assert.That(mappedClass.UniqueConstraints.Count, Is.EqualTo(1));
            Assert.That(uniqueConstraint, Is.Not.Null);
            Assert.That(uniqueConstraint.Properties.Contains(dbKey.KeyColumns[0].Column.GetMappedDMProperty()));
            Assert.That(table.Keys.Count, Is.EqualTo(1));
            //---------------Execute Test ----------------------
            importer.ImportDBChanges(table.Database, (DMSolution) mappedClass.Solution);
            //---------------Test Result -----------------------
            Assert.AreEqual(0, mappedClass.UniqueConstraints.Count);
            Assert.IsTrue(uniqueConstraint.Status.IsDeleted);
            Assert.AreEqual(0, table.Keys.Count);
            Assert.IsTrue(dbKey.Status.IsDeleted);
        }

        [Test]
        public void Test_ImportDBChanges_DeletedDBKey_ShouldNotDeleteUnapproved()
        {
            //---------------Set up test pack-------------------
            IDBChangesImporter importer = CreateDBChangesImporter();
            DBKey dbKey = CreateAlternateKeyWithMappedUniqueConstraint().UnApproveForDelete();
            DBTable table = (DBTable)dbKey.Table;
            DMClass mappedClass = table.GetMappedDMClass();
            DMUniqueConstraint uniqueConstraint = mappedClass.UniqueConstraints[0];
            //---------------Assert Precondition----------------
            Assert.That(mappedClass.UniqueConstraints.Count, Is.EqualTo(1));
            Assert.That(uniqueConstraint, Is.Not.Null);
            Assert.That(uniqueConstraint.Properties.Contains(dbKey.KeyColumns[0].Column.GetMappedDMProperty()));
            Assert.That(table.Keys.Count, Is.EqualTo(1));
            //---------------Execute Test ----------------------
            importer.ImportDBChanges(table.Database, (DMSolution) mappedClass.Solution);
            //---------------Test Result -----------------------
            Assert.That(mappedClass.UniqueConstraints.Count, Is.EqualTo(1));
            Assert.That(table.Keys.Count, Is.EqualTo(1));
            dbKey.AssertIsUnApprovedAndPendingChangeTypeIs(ChangeType.Delete);
        }

        [Test]
        public void Test_ImportDBChanges_DeletedDBForeignKey_ShouldDeleteApproved()
        {
            //---------------Set up test pack-------------------
            IDBChangesImporter importer = CreateDBChangesImporter();
            DBForeignKey foreignKey = CreateForeignKeyWithMappedRelationship().ApproveForDelete();
            DBTable parentTable = foreignKey.ParentTable;
            DMClass parentClass = parentTable.GetMappedDMClass();
            DMRelationship relationship = foreignKey.GetMappedDMRelationship();
            //---------------Assert Precondition----------------
            Assert.AreEqual(1, relationship.RelationshipProperties.Count);
            Assert.AreEqual(1, parentTable.ForeignKeys.Count);
            //---------------Execute Test ----------------------
            importer.ImportDBChanges(parentTable.Database, (DMSolution) parentClass.Solution);
            //---------------Test Result -----------------------
            Assert.AreEqual(0, relationship.RelationshipProperties.Count);
            Assert.AreEqual(0, parentTable.ForeignKeys.Count);
        }

        [Test]
        public void Test_ImportDBChanges_DeletedDBForeignKey_ShouldNotDeleteUnapproved()
        {
            //---------------Set up test pack-------------------
            IDBChangesImporter importer = CreateDBChangesImporter();
            DBForeignKey foreignKey = CreateForeignKeyWithMappedRelationship().UnApproveForDelete();
            DBTable parentTable = foreignKey.ParentTable;
            DMClass parentClass = parentTable.GetMappedDMClass();
            DMRelationship relationship = foreignKey.GetMappedDMRelationship();
            //---------------Assert Precondition----------------
            Assert.AreEqual(1, relationship.RelationshipProperties.Count);
            Assert.AreEqual(1, parentTable.ForeignKeys.Count);
            //---------------Execute Test ----------------------
            importer.ImportDBChanges(parentTable.Database, (DMSolution) parentClass.Solution);
            //---------------Test Result -----------------------
            Assert.AreEqual(1, relationship.RelationshipProperties.Count);
            Assert.AreEqual(1, parentTable.ForeignKeys.Count);
            foreignKey.AssertIsUnApprovedAndPendingChangeTypeIs(ChangeType.Delete);
        }
    }
}